package cn.iocoder.yudao.module.system.util.gugu;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 选科组合计算工具类
 */
@Slf4j
public class SubjectCombinationCalculator {

    // 所有可选科目
    private static final List<String> ALL_SUBJECTS = Arrays.asList("物理", "化学", "生物", "历史", "地理", "政治");
    
    // 常见的选科组合
    private static final List<List<String>> COMMON_COMBINATIONS = Arrays.asList(
            Arrays.asList("物理", "化学", "生物"),  // 理化生
            Arrays.asList("物理", "化学", "地理"),  // 理化地
            Arrays.asList("物理", "化学", "政治"),  // 理化政
            Arrays.asList("物理", "生物", "地理"),  // 理生地
            Arrays.asList("物理", "生物", "政治"),  // 理生政
            Arrays.asList("物理", "地理", "政治"),  // 理地政
            Arrays.asList("历史", "地理", "政治"),  // 史地政
            Arrays.asList("历史", "化学", "生物"),  // 史化生
            Arrays.asList("历史", "化学", "地理"),  // 史化地
            Arrays.asList("历史", "化学", "政治"),  // 史化政
            Arrays.asList("历史", "生物", "地理"),  // 史生地
            Arrays.asList("历史", "生物", "政治")   // 史生政
    );

    /**
     * 选科组合分析结果
     */
    @Data
    public static class CombinationAnalysis {
        private List<String> combination;
        private int coverageCount;
        private double coverageRate;
        private int totalRequirements;
        private String description;
    }

    /**
     * 计算最优选科组合
     * @param subjectRequirements 选科要求列表
     * @return 最优选科组合分析结果
     */
    public static CombinationAnalysis calculateOptimalCombination(List<String> subjectRequirements) {
        if (subjectRequirements == null || subjectRequirements.isEmpty()) {
            return createDefaultCombination();
        }

        log.info("开始计算最优选科组合，选科要求数量：{}", subjectRequirements.size());

        // 统计每个科目的出现频次
        Map<String, Integer> subjectFrequency = analyzeSubjectFrequency(subjectRequirements);
        log.debug("科目频次统计：{}", subjectFrequency);

        // 评估所有常见组合
        List<CombinationAnalysis> analyses = new ArrayList<>();
        for (List<String> combination : COMMON_COMBINATIONS) {
            CombinationAnalysis analysis = evaluateCombination(combination, subjectRequirements, subjectFrequency);
            analyses.add(analysis);
        }

        // 选择覆盖率最高的组合
        CombinationAnalysis bestCombination = analyses.stream()
                .max(Comparator.comparingDouble(CombinationAnalysis::getCoverageRate))
                .orElse(createDefaultCombination());

        log.info("最优选科组合：{}，覆盖率：{:.1f}%", 
                bestCombination.getCombination(), bestCombination.getCoverageRate());

        return bestCombination;
    }

    /**
     * 分析科目频次
     */
    private static Map<String, Integer> analyzeSubjectFrequency(List<String> subjectRequirements) {
        Map<String, Integer> frequency = new HashMap<>();
        
        for (String requirement : subjectRequirements) {
            if (!StringUtils.hasText(requirement) || "不限".equals(requirement)) {
                continue;
            }

            Set<String> subjects = parseSubjectsFromRequirement(requirement);
            for (String subject : subjects) {
                frequency.merge(subject, 1, Integer::sum);
            }
        }

        return frequency;
    }

    /**
     * 从选科要求中解析科目
     */
    private static Set<String> parseSubjectsFromRequirement(String requirement) {
        Set<String> subjects = new HashSet<>();
        
        // 科目名称映射
        Map<String, String> subjectMapping = new HashMap<>();
        subjectMapping.put("物理", "物理");
        subjectMapping.put("化学", "化学");
        subjectMapping.put("生物", "生物");
        subjectMapping.put("历史", "历史");
        subjectMapping.put("地理", "地理");
        subjectMapping.put("政治", "政治");
        subjectMapping.put("思想政治", "政治");
        // 简写形式映射
        subjectMapping.put("史", "历史");
        subjectMapping.put("政", "政治");
        subjectMapping.put("物", "物理");
        subjectMapping.put("化", "化学");
        subjectMapping.put("生", "生物");
        subjectMapping.put("地", "地理");

        // 按照长度排序，优先匹配长的科目名称（避免"思想政治"被"政治"覆盖）
        List<Map.Entry<String, String>> sortedEntries = subjectMapping.entrySet().stream()
                .sorted((e1, e2) -> Integer.compare(e2.getKey().length(), e1.getKey().length()))
                .collect(Collectors.toList());

        for (Map.Entry<String, String> entry : sortedEntries) {
            if (requirement.contains(entry.getKey())) {
                subjects.add(entry.getValue());
            }
        }

        return subjects;
    }

    /**
     * 评估选科组合
     */
    private static CombinationAnalysis evaluateCombination(List<String> combination, 
                                                          List<String> subjectRequirements,
                                                          Map<String, Integer> subjectFrequency) {
        CombinationAnalysis analysis = new CombinationAnalysis();
        analysis.setCombination(new ArrayList<>(combination));
        analysis.setTotalRequirements(subjectRequirements.size());

        int coverageCount = 0;
        
        // 计算该组合能覆盖多少个选科要求
        for (String requirement : subjectRequirements) {
            if (!StringUtils.hasText(requirement) || "不限".equals(requirement)) {
                coverageCount++; // 不限要求任何组合都能满足
                continue;
            }

            if (canSatisfyRequirement(combination, requirement)) {
                coverageCount++;
            }
        }

        analysis.setCoverageCount(coverageCount);
        analysis.setCoverageRate(subjectRequirements.isEmpty() ? 100.0 : 
                (double) coverageCount / subjectRequirements.size() * 100);

        // 生成描述
        String combinationStr = String.join("、", combination);
        analysis.setDescription(String.format("选科组合：%s，覆盖%d/%d个专业要求", 
                combinationStr, coverageCount, subjectRequirements.size()));

        return analysis;
    }

    /**
     * 检查选科组合是否能满足要求
     */
    private static boolean canSatisfyRequirement(List<String> combination, String requirement) {
        Set<String> combinationSet = new HashSet<>(combination);

        // 处理不限要求
        if ("不限".equals(requirement.trim()) || "首选不限，再选不限".equals(requirement.trim())) {
            return true;
        }

        // 处理首选+再选要求
        if (requirement.contains("首选") && requirement.contains("再选")) {
            return checkFirstAndSecondChoice(combinationSet, requirement);
        }

        // 处理必选要求（包括多科必选）
        if (requirement.contains("必选")) {
            return checkRequiredSubjects(combinationSet, requirement);
        }

        // 处理选择要求（如2选1、3选1等）
        if (requirement.contains("选1")) {
            return checkSelectOneRequirement(combinationSet, requirement);
        }

        // 默认处理：解析科目并检查是否有交集
        Set<String> requiredSubjects = parseSubjectsFromRequirement(requirement);
        return !requiredSubjects.isEmpty() &&
               requiredSubjects.stream().anyMatch(combinationSet::contains);
    }

    /**
     * 检查首选+再选要求
     */
    private static boolean checkFirstAndSecondChoice(Set<String> combination, String requirement) {
        // 检查首选科目
        boolean firstChoiceMet = false;
        if (requirement.contains("首选物理") && combination.contains("物理")) {
            firstChoiceMet = true;
        } else if (requirement.contains("首选历史") && combination.contains("历史")) {
            firstChoiceMet = true;
        } else if (requirement.contains("首选不限")) {
            firstChoiceMet = true;
        }

        if (!firstChoiceMet) {
            return false;
        }

        // 检查再选科目
        if (requirement.contains("再选不限")) {
            return true;
        }

        // 解析再选要求
        String reSelectPart = requirement.substring(requirement.indexOf("再选") + 2);
        return checkSecondChoiceRequirement(combination, reSelectPart);
    }

    /**
     * 检查再选要求
     */
    private static boolean checkSecondChoiceRequirement(Set<String> combination, String reSelectPart) {
        // 处理再选的必选要求
        if (reSelectPart.contains("必选")) {
            return checkRequiredSubjects(combination, reSelectPart);
        }

        // 处理再选的选择要求
        if (reSelectPart.contains("选1")) {
            return checkSelectOneRequirement(combination, reSelectPart);
        }

        // 处理单个科目再选
        Set<String> reSelectSubjects = parseSubjectsFromRequirement(reSelectPart);
        return reSelectSubjects.isEmpty() ||
               reSelectSubjects.stream().anyMatch(combination::contains);
    }

    /**
     * 检查必选科目要求
     */
    private static boolean checkRequiredSubjects(Set<String> combination, String requirement) {
        // 处理多科必选的情况，如"化学、生物(2科必选)"
        if (requirement.contains("科必选")) {
            return checkMultipleRequiredSubjects(combination, requirement);
        }

        // 处理单科必选的情况，如"物理必选"
        Set<String> requiredSubjects = parseSubjectsFromRequirement(requirement);
        return combination.containsAll(requiredSubjects);
    }

    /**
     * 检查多科必选要求
     */
    private static boolean checkMultipleRequiredSubjects(Set<String> combination, String requirement) {
        Set<String> requiredSubjects = parseSubjectsFromRequirement(requirement);

        // 提取必选科目数量
        int requiredCount = 0;
        if (requirement.contains("2科必选")) {
            requiredCount = 2;
        } else if (requirement.contains("3科必选")) {
            requiredCount = 3;
        } else {
            // 默认为全部必选
            return combination.containsAll(requiredSubjects);
        }

        // 计算组合中包含的必选科目数量
        int matchCount = 0;
        for (String subject : requiredSubjects) {
            if (combination.contains(subject)) {
                matchCount++;
            }
        }

        return matchCount >= requiredCount;
    }

    /**
     * 检查选择要求（如2选1、3选1等）
     */
    private static boolean checkSelectOneRequirement(Set<String> combination, String requirement) {
        // 解析选择要求中的科目
        Set<String> selectSubjects = parseSubjectsFromRequirement(requirement);
        // 至少选择一个科目即可满足
        return selectSubjects.stream().anyMatch(combination::contains);
    }

    /**
     * 创建默认组合（当没有选科要求时）
     */
    private static CombinationAnalysis createDefaultCombination() {
        CombinationAnalysis analysis = new CombinationAnalysis();
        analysis.setCombination(Arrays.asList("物理", "化学", "生物")); // 默认理化生组合
        analysis.setCoverageCount(0);
        analysis.setCoverageRate(100.0);
        analysis.setTotalRequirements(0);
        analysis.setDescription("默认推荐组合：物理、化学、生物");
        return analysis;
    }

    /**
     * 获取推荐的选科组合（前N个）
     */
    public static List<CombinationAnalysis> getTopCombinations(List<String> subjectRequirements, int topN) {
        if (subjectRequirements == null || subjectRequirements.isEmpty()) {
            return Arrays.asList(createDefaultCombination());
        }

        Map<String, Integer> subjectFrequency = analyzeSubjectFrequency(subjectRequirements);
        
        return COMMON_COMBINATIONS.stream()
                .map(combination -> evaluateCombination(combination, subjectRequirements, subjectFrequency))
                .sorted(Comparator.comparingDouble(CombinationAnalysis::getCoverageRate).reversed())
                .limit(topN)
                .collect(Collectors.toList());
    }
}
